From a347e374cb338213632c6dde88dd226d64bd8b27 Mon Sep 17 00:00:00 2001
From: Weijie Gao <weijie.gao@mediatek.com>
Date: Wed, 3 Mar 2021 08:57:29 +0800
Subject: [PATCH 37/71] mtd: mtk-snand: add support for SPL

Add support to initialize SPI-NAND in SPL.
Add implementation for SPL NAND loader.

Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
---
 drivers/mtd/mtk-snand/Kconfig         |   6 ++
 drivers/mtd/mtk-snand/Makefile        |   4 +
 drivers/mtd/mtk-snand/mtk-snand-spl.c | 133 ++++++++++++++++++++++++++
 3 files changed, 143 insertions(+)
 create mode 100644 drivers/mtd/mtk-snand/mtk-snand-spl.c

--- a/drivers/mtd/mtk-snand/Kconfig
+++ b/drivers/mtd/mtk-snand/Kconfig
@@ -19,3 +19,9 @@ config MTK_SPI_NAND_MTD
 	help
 	  This option enables access to SPI-NAND flashes through the
 	  MTD interface of MediaTek SPI NAND Flash Controller
+
+config SPL_MTK_SPI_NAND
+	tristate "SPL support for MediaTek SPI NAND flash controller"
+	depends on MTK_SPI_NAND
+	help
+	  This option enables access to SPI-NAND flashes in the SPL stage
--- a/drivers/mtd/mtk-snand/Makefile
+++ b/drivers/mtd/mtk-snand/Makefile
@@ -8,4 +8,8 @@
 obj-y += mtk-snand.o mtk-snand-ecc.o mtk-snand-ids.o mtk-snand-os.o
 obj-$(CONFIG_MTK_SPI_NAND_MTD) += mtk-snand-mtd.o
 
+ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_SPL_MTK_SPI_NAND) += mtk-snand-spl.o
+endif
+
 ccflags-y += -DPRIVATE_MTK_SNAND_HEADER
--- /dev/null
+++ b/drivers/mtd/mtk-snand/mtk-snand-spl.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/uclass.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <mtd.h>
+#include <watchdog.h>
+
+#include "mtk-snand.h"
+
+static struct mtk_snand *snf;
+static struct mtk_snand_chip_info cinfo;
+static u32 oobavail;
+
+static u8 *page_cache;
+
+int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
+{
+	u32 sizeremain = size, chunksize, leading;
+	uint32_t off = offs, writesize_mask = cinfo.pagesize - 1;
+	uint8_t *ptr = dst;
+	int ret;
+
+	if (!snf)
+		return -ENODEV;
+
+	while (sizeremain) {
+		schedule();
+
+		leading = off & writesize_mask;
+		chunksize = cinfo.pagesize - leading;
+		if (chunksize > sizeremain)
+			chunksize = sizeremain;
+
+		if (chunksize == cinfo.pagesize) {
+			ret = mtk_snand_read_page(snf, off - leading, ptr,
+						  NULL, false);
+			if (ret)
+				break;
+		} else {
+			ret = mtk_snand_read_page(snf, off - leading,
+						  page_cache, NULL, false);
+			if (ret)
+				break;
+
+			memcpy(ptr, page_cache + leading, chunksize);
+		}
+
+		off += chunksize;
+		ptr += chunksize;
+		sizeremain -= chunksize;
+	}
+
+	return ret;
+}
+
+void nand_init(void)
+{
+	struct mtk_snand_platdata mtk_snand_pdata = {};
+	struct udevice *dev;
+	fdt_addr_t base;
+	int ret;
+
+	ret = uclass_get_device_by_driver(UCLASS_MTD, DM_DRIVER_GET(mtk_snand),
+					  &dev);
+	if (ret) {
+		printf("mtk-snand-spl: Device instance not found!\n");
+		return;
+	}
+
+	base = dev_read_addr_name(dev, "nfi");
+	if (base == FDT_ADDR_T_NONE) {
+		printf("mtk-snand-spl: NFI base not set\n");
+		return;
+	}
+	mtk_snand_pdata.nfi_base = map_sysmem(base, 0);
+
+	base = dev_read_addr_name(dev, "ecc");
+	if (base == FDT_ADDR_T_NONE) {
+		printf("mtk-snand-spl: ECC base not set\n");
+		return;
+	}
+	mtk_snand_pdata.ecc_base = map_sysmem(base, 0);
+
+	mtk_snand_pdata.soc = dev_get_driver_data(dev);
+	mtk_snand_pdata.quad_spi = dev_read_bool(dev, "quad-spi");
+
+	ret = mtk_snand_init(NULL, &mtk_snand_pdata, &snf);
+	if (ret) {
+		printf("mtk-snand-spl: failed to initialize SPI-NAND\n");
+		return;
+	}
+
+	mtk_snand_get_chip_info(snf, &cinfo);
+
+	oobavail = cinfo.num_sectors * (cinfo.fdm_size - 1);
+
+	printf("SPI-NAND: %s (%uMB)\n", cinfo.model,
+	       (u32)(cinfo.chipsize >> 20));
+
+	page_cache = malloc(cinfo.pagesize + cinfo.sparesize);
+	if (!page_cache) {
+		mtk_snand_cleanup(snf);
+		printf("mtk-snand-spl: failed to allocate page cache\n");
+	}
+}
+
+void nand_deselect(void)
+{
+
+}
+
+static const struct udevice_id mtk_snand_ids[] = {
+	{ .compatible = "mediatek,mt7622-snand", .data = SNAND_SOC_MT7622 },
+	{ .compatible = "mediatek,mt7629-snand", .data = SNAND_SOC_MT7629 },
+	{ .compatible = "mediatek,mt7981-snand", .data = SNAND_SOC_MT7981 },
+	{ .compatible = "mediatek,mt7986-snand", .data = SNAND_SOC_MT7986 },
+	{ /* sentinel */ },
+};
+
+U_BOOT_DRIVER(mtk_snand) = {
+	.name = "mtk-snand",
+	.id = UCLASS_MTD,
+	.of_match = mtk_snand_ids,
+	.flags = DM_FLAG_PRE_RELOC,
+};
